package com.smartfast4j.qiniu;

import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;
import com.qiniu.util.StringUtils;
import org.apache.log4j.Logger;

import java.io.File;
import java.util.*;

/**
 * Created by gacl on 2017/10/23.
 */
public class QiNiuClient {

    private static Logger LOG = Logger.getLogger(QiNiuClient.class);

    //文件上传token
    private static String uptoken = null;
    // 重用 uploadManager。一般地，只需要创建一个 uploadManager 对象
    private final static UploadManager uploadManager = new UploadManager(new Configuration(Zone.zone0()));
    private static BucketManager bucketManager;
    private static String bucket;
    private static Auth auth;

    private QiNiuConfig qiNiuConfig;

    public QiNiuClient(String configFilePath){
        init(configFilePath);
    }

    private void init(String configFilePath){
        String baseName = configFilePath.substring(0, configFilePath.lastIndexOf("."));
        ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName);
        qiNiuConfig = new QiNiuConfig();
        qiNiuConfig.setAccessKey(resourceBundle.getString("qiniu.accessKey"));
        qiNiuConfig.setSecretKey(resourceBundle.getString("qiniu.secretKey"));
        qiNiuConfig.setBucket(resourceBundle.getString("qiniu.bucket"));
        qiNiuConfig.setServerDomain(resourceBundle.getString("qiniu.server.domain"));
        try {
            String ak = qiNiuConfig.getAccessKey();
            String sk = qiNiuConfig.getSecretKey();
            bucket = qiNiuConfig.getBucket();
            if (!StringUtils.isNullOrEmpty(ak) && !StringUtils.isNullOrEmpty(sk)) {
                auth = Auth.create(ak, sk);
                //通过七牛提供的SDK获取文件上传token，token的有效期是3600秒，也就是一个小时，所以一小时后要重新获取一次uptoken
                uptoken = auth.uploadToken(bucket);
                LOG.info("获取文件上传token:"+uptoken);
                bucketManager = new BucketManager(auth,new Configuration(Zone.zone0()));
            }
        } catch (Exception e) {
            LOG.error("init qiniu error", e);
        }
    }

    /**
     * 上传文件
     *
     * @param byteOrFile
     * @param fileName
     * @throws Exception
     */
    public void uploadFile(byte[] byteOrFile, String fileName) throws Exception {
        uploadFile(byteOrFile,fileName,false);
    }

    /**
     * 上传文件
     *
     * @param byteOrFile
     * @param fileName
     * @throws Exception
     */
    public void uploadFile(byte[] byteOrFile, String fileName,boolean overwrite) throws Exception {
        try {
            if (fileName.startsWith("/"))
                fileName = fileName.substring(1, fileName.length());
            String token = getToken(fileName, overwrite);
            Response res = uploadManager.put(byteOrFile, fileName, token);
            if (res.isOK()) {
                // System.out.println(res);
                LOG.debug("upload success");
            } else {
                throw new Exception("status:" + res.statusCode + ",error:" + res.error);
            }
        } catch (QiniuException e) {
            LOG.error(e.getMessage(), e);
            Response r = e.response;
            // 请求失败时简单状态信息
            LOG.error(r.error);
            // 响应的文本信息
            LOG.error(r.bodyString());
            throw e;
        }
    }

    /**
     * 文件上传
     * @param byteOrFile
     * @param fileName
     * @throws QiniuException
     */
    public void uploadFile(File byteOrFile, String fileName)
            throws QiniuException {
        uploadFile(byteOrFile,fileName,false);
    }

    /**
     * 文件上传
     * @param byteOrFile
     * @param fileName
     * @param overwrite
     * @throws QiniuException
     */
    public void uploadFile(File byteOrFile, String fileName, boolean overwrite)
            throws QiniuException {
        try {
            if (fileName.startsWith("/"))
                fileName = fileName.substring(1, fileName.length());
            String token = getToken(fileName, overwrite);
            Response res = uploadManager.put(byteOrFile, fileName, token);
            if (res.isOK()) {
                // System.out.println(res);
                LOG.debug("upload success");
            } else {
                throw new RuntimeException("status:" + res.statusCode + ",error:" + res.error);
            }
        } catch (QiniuException e) {
            LOG.error(e.getMessage(), e);
            Response r = e.response;
            // 请求失败时简单状态信息
            LOG.error(r.error);
            LOG.error(r.bodyString());
            throw e;
        }
    }

    /**
     * 删除文件
     * @param fileName
     */
    public void delete(String fileName) throws QiniuException{
        bucketManager.delete(bucket,fileName);
    }

    /**
     * 批量删除
     * @param lstFileName
     */
    public Map<String,Integer> batchDelete(List<String> lstFileName) throws QiniuException {
        Map<String,Integer> resultMap = new HashMap<>();
        //单次批量请求的文件数量不得超过1000
        String[] keyList = new String[lstFileName.size()];
        for(int i=0;i<lstFileName.size();i++){
            keyList[i] = lstFileName.get(i);
        }
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        batchOperations.addDeleteOp(bucket, keyList);
        Response response = bucketManager.batch(batchOperations);//批量删除
        BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
        for (int i = 0; i < keyList.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = keyList[i];
            System.out.print(key + "\t");
            if (status.code == 200) {
                System.out.println("delete success");
                resultMap.put(key,0);//删除成功
            } else {
                System.out.println(status.data.error);
                resultMap.put(key,-1);//删除失败
            }
        }
        return resultMap;
    }

    private String getToken(String key, boolean overwrite) {
        return overwrite ? auth.uploadToken(bucket, key) : uptoken;
    }

    public List<String> listFile(String prefix, int limit, String delimiter) {
        BucketManager.FileListIterator it = bucketManager.createFileListIterator(bucket, prefix,
                limit, delimiter);
        List<String> list = new ArrayList<>();
        while (it.hasNext()) {
            FileInfo[] items = it.next();
            if (items.length > 0) {
                for (int i = 0; i < items.length; i++) {
                    FileInfo fi = items[i];
                    if (fi != null) {
                        list.add(fi.key);
                    }
                }
            }
        }
        return list;
    }

    public QiNiuConfig getQiNiuConfig() {
        return qiNiuConfig;
    }

    public void setQiNiuConfig(QiNiuConfig qiNiuConfig) {
        this.qiNiuConfig = qiNiuConfig;
    }
}
